﻿using System;
using System.Collections.Generic;
using System.Web.Mvc;
using CodeCamp.Infrastructure;
using CodeCamp.Models.Schedule;
using CodeCamp.Models.Shared;
using System.Linq;
using RGoodSW.Logger.Interfaces;
using CCM = CodeCamp.Model;

namespace CodeCamp.Controllers
{
  public class ScheduleController : ControllerBase
  {
    public ScheduleController(IDefaultValueProvider defaultValueProvider, ILoggerExtended logger)
      : base(defaultValueProvider, logger)
    {
    }

    public ActionResult Agenda( string eventName )
    {
      using (var repository = new CodeCampDataRepository())
      {
          var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
          if (ccEvent.ShortName != eventName)
              return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

          if (!ccEvent.AgendaIsPublic
              && !User.IsInRole(CCRoles.RoleNames.BigCheeze) && !User.IsInRole(CCRoles.RoleNames.EventContentEditor)
               && !User.IsInRole(CCRoles.RoleNames.EventTrackLead))
          {
              return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });
          }

          var model = new ScheduleAgendaViewModel();

          string partialName = string.Format("Partial/{0}AgendaPartial", ccEvent.ShortName);
          ViewEngineResult partial = ViewEngines.Engines.FindView(this.ControllerContext, partialName, null);
          if ((partial != null) && (partial.View != null))
              model.AgendaPartialView = partialName;

          SetSharedEventProperties(ccEvent, model, repository);

          return View(model);
      }
    }


    protected bool CanShowSchedule(CCM.Event ccEvent)
    {
        bool showSchedule = (ccEvent.ScheduleIsPublic
            || (ccEvent.ScheduleVisibleToPresenters && User.IsInRole(CCRoles.RoleNames.Presenter))
            || User.IsInRole(CCRoles.RoleNames.BigCheeze) || User.IsInRole(CCRoles.RoleNames.EventContentEditor)
             || User.IsInRole(CCRoles.RoleNames.EventTrackLead));

        return showSchedule;
    }

    public ActionResult Index( string eventName )
    {
      using (var repository = new CodeCampDataRepository())
      {
          var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
          if (ccEvent.ShortName != eventName)
              return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

          if (!CanShowSchedule(ccEvent))
          {
              return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });
          }

          Dictionary<int, string> roomInfoDict = new Dictionary<int, string>();
          int buildingCount = 0;
          List<int> floors = new List<int>();
          List<ScheduleRoomsViewModel.Building> buildings = new List<ScheduleRoomsViewModel.Building>();
          foreach (var building in repository.EFContext.Buildings.OrderBy(b => b.Name).Where(b => b.EventId == ccEvent.Id))
          {
              buildingCount++;
              foreach (var room in building.Rooms)
              {
                  if ((room.Floor.HasValue) && !floors.Contains(room.Floor.Value))
                  {
                      floors.Add(room.Floor.Value);
                  }
              }
          }
          foreach (var building in repository.EFContext.Buildings.OrderBy(b => b.Name).Where(b => b.EventId == ccEvent.Id))
          {
              foreach (var room in building.Rooms)
              {
                  System.Text.StringBuilder roomInfo = new System.Text.StringBuilder();
                  if (buildingCount > 1)
                  {
                      roomInfo.Append(building.Name);
                      roomInfo.Append(", ");
                  }
                  if (room.Floor.HasValue)
                      roomInfo.AppendFormat("fl {0}: ", room.Floor);
                  roomInfo.Append(room.Name);
                  if (room.Capacity > 0)
                      roomInfo.AppendFormat(" (seats {0})", room.Capacity);

                  roomInfoDict.Add(room.Id, roomInfo.ToString());
              }
          }

          int eventId = ccEvent.Id;

          var timeslotList = new List<ScheduleIndexViewModel.Timeslot>();
          var timeslots = repository.GetTimeslots(eventId);
          foreach (var timeslot in timeslots)
          {
              var sessionList = new List<ScheduleIndexViewModel.Timeslot.Session>();
              var scheduledSessions = timeslot.ScheduledSessions.OrderBy(ss => ss.Session.Title);
              foreach (var scheduledSession in scheduledSessions)
              {
                  var session = scheduledSession.Session;

                  var presenters =
                    (
                      from sp in session.SessionPresenters
                      orderby sp.Presenter.LastName
                      select new ScheduleIndexViewModel.Timeslot.Session.Presenter
                      {
                          PresenterId = sp.PresenterId,
                          Name = string.Format("{0} {1}", sp.Presenter.FirstName, sp.Presenter.LastName)
                      }
                    ).ToList();

                  string roomInfo = null;

                  if (roomInfoDict.ContainsKey(scheduledSession.RoomId))
                      roomInfo = roomInfoDict[scheduledSession.RoomId];

                  if (string.IsNullOrWhiteSpace(roomInfo))
                      roomInfo = scheduledSession.Room.Name;

                  sessionList.Add(
                    new ScheduleIndexViewModel.Timeslot.Session
                    {
                        SessionId = session.Id,
                        Title = SessionTitle(scheduledSession.Session), //SessionsController.FilterDevSatTag(session.Title),
                        Presenters = presenters,
                        Building = scheduledSession.Room.Building.Name,
                        Floor = scheduledSession.Room.Floor,
                        Room = scheduledSession.Room.Name,
                        RoomId = scheduledSession.RoomId,
                        RoomInfo = roomInfo
                    });
              }

              timeslotList.Add(
                new ScheduleIndexViewModel.Timeslot
                {
                    TimeslotId = timeslot.Id,
                    Name = timeslot.Name,
                    Date = timeslot.Date,
                    StartTime = DateTimeHelper.CombineDateAndTime(timeslot.Date, timeslot.StartTime),
                    EndTime = DateTimeHelper.CombineDateAndTime(timeslot.Date, timeslot.EndTime),
                    Sessions = sessionList
                });
          }

          var model =
            new ScheduleIndexViewModel
            {
                BuildingCount = buildingCount,
                FloorCount = floors.Count,
                Timeslots = timeslotList
            };
          SetSharedEventProperties(ccEvent, model, repository);

          return View(model);
      }
    }

    public ActionResult Rooms( string eventName )
    {
      using (var repository = new CodeCampDataRepository())
      {
          var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
          if (ccEvent.ShortName != eventName)
              return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

          if (!CanShowSchedule(ccEvent))
          {
              return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });
          }

          List<ScheduleRoomsViewModel.Building> buildings = new List<ScheduleRoomsViewModel.Building>();
          foreach (var building in repository.EFContext.Buildings.OrderBy(b => b.Name).Where(b => b.EventId == ccEvent.Id))
          {
              var viewBuilding = new ScheduleRoomsViewModel.Building
              {
                  Name = building.Name,
                  Rooms = new List<ScheduleRoomsViewModel.Building.Room>()
              };
              foreach (var room in building.Rooms)
              {
                  System.Text.StringBuilder roomInfo = new System.Text.StringBuilder();
                  if (room.Floor.HasValue)
                      roomInfo.AppendFormat(" - floor {0}", room.Floor);
                  if (room.Capacity > 0)
                  {
                      if (roomInfo.Length > 0)
                          roomInfo.Append(", ");
                      else
                          roomInfo.Append(" - ");
                      roomInfo.AppendFormat("seats {0}", room.Capacity);
                  }

                  var viewRoom = new ScheduleRoomsViewModel.Building.Room
                  {
                      Name = room.Name,
                      RoomId = room.Id,
                      RoomInfo = roomInfo.ToString(),
                      Sessions = new List<ScheduleRoomsViewModel.Building.Room.Session>()
                  };
                  foreach (var scheduledSession in room.ScheduledSessions)
                  {
                      var viewSession = new ScheduleRoomsViewModel.Building.Room.Session
                      {
                          EndTime = DateTimeHelper.CombineDateAndTime(scheduledSession.Timeslot.Date, scheduledSession.Timeslot.EndTime),
                          SessionId = scheduledSession.SessionId,
                          StartTime = DateTimeHelper.CombineDateAndTime(scheduledSession.Timeslot.Date, scheduledSession.Timeslot.StartTime),
                          Title = SessionTitle(scheduledSession.Session),
                          Presenters = new List<ScheduleRoomsViewModel.Building.Room.Session.Presenter>()
                      };
                      foreach (var sessionPresenter in scheduledSession.Session.SessionPresenters)
                      {
                          var viewPresenter = new ScheduleRoomsViewModel.Building.Room.Session.Presenter
                          {
                              Name = string.Format("{0} {1}", sessionPresenter.Presenter.FirstName, sessionPresenter.Presenter.LastName),
                              PresenterId = sessionPresenter.PresenterId
                          };
                          viewSession.Presenters.Add(viewPresenter);
                      }
                      viewRoom.Sessions.Add(viewSession);
                  }
                  if (viewRoom.Sessions.Count > 0)
                    viewBuilding.Rooms.Add(viewRoom);
              }
              buildings.Add(viewBuilding);
          }
          var model = new ScheduleRoomsViewModel
          {
              Buildings = buildings.ToList() as List<ScheduleRoomsViewModel.Building>
          };
          SetSharedEventProperties(ccEvent, model, repository);

          return View(model);
      }
    }

    public ActionResult Room(string eventName, int id)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (!CanShowSchedule(ccEvent))
            {
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });
            }

            int eventId = ccEvent.Id;

            var room = repository.GetRoomWithScheduledSessions(id);

            if (room == null)
                return RedirectToAction("Rooms", new { eventName = ccEvent.ShortName });

            var sessions = new List<ScheduleRoomViewModel.Session>();

            foreach (var ss in room.ScheduledSessions)
            {
                var viewSession = new ScheduleRoomViewModel.Session
                {
                    SessionId = ss.SessionId,
                    Title = SessionsController.FilterDevSatTag(ss.Session.Title),
                    StartTime = DateTimeHelper.CombineDateAndTime(ss.Timeslot.Date, ss.Timeslot.StartTime),
                    EndTime = DateTimeHelper.CombineDateAndTime(ss.Timeslot.Date, ss.Timeslot.EndTime),
                    Presenters = new List<ScheduleRoomViewModel.Session.Presenter>()
                };

                foreach (var sp in ss.Session.SessionPresenters)
                {
                    var viewPresenter = new ScheduleRoomViewModel.Session.Presenter
                    {
                        PresenterId = sp.PresenterId,
                        Name = string.Format("{0} {1}", sp.Presenter.FirstName, sp.Presenter.LastName)
                    };
                    viewSession.Presenters.Add(viewPresenter);
                }
                sessions.Add(viewSession);
            }

#if false
          var sessions =
            (
              from scheduledSession in room.ScheduledSessions
              orderby scheduledSession.Timeslot.StartTime
              select new ScheduleRoomViewModel.Session
              {
                  SessionId = scheduledSession.SessionId,
                  Title = SessionsController.FilterDevSatTag(scheduledSession.Session.Title),
                  StartTime = DateTimeHelper.CombineDateAndTime(scheduledSession.Timeslot.Date, scheduledSession.Timeslot.StartTime),
                  EndTime = DateTimeHelper.CombineDateAndTime(scheduledSession.Timeslot.Date, scheduledSession.Timeslot.EndTime),

                  Presenters =
                  (
                    from presenter in scheduledSession.Session.SessionPresenters
                    orderby presenter.Presenter.LastName
                    select new ScheduleRoomViewModel.Session.Presenter
                    {
                        PresenterId = presenter.PresenterId,
                        Name = string.Format("{0} {1}", presenter.Presenter.FirstName, presenter.Presenter.LastName)
                    }
                  ).ToList()
              }
            ).ToList();
#endif
            System.Text.StringBuilder roomInfo = new System.Text.StringBuilder();
            if (room.Floor.HasValue)
                roomInfo.AppendFormat("floor: {0}", room.Floor);
            if (room.Capacity > 0)
            {
                if (roomInfo.Length > 0)
                    roomInfo.Append(", ");
                roomInfo.AppendFormat("seats {0}", room.Capacity);
            }

            var model = new ScheduleRoomViewModel
            {
                Building = room.Building.Name,
                Room = room.Name,
                RoomInfo = roomInfo.ToString(),
                Sessions = sessions
            };
            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }

    public ActionResult Hotels(string eventName)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (!ccEvent.ScheduleIsPublic
                && !User.IsInRole(CCRoles.RoleNames.BigCheeze) && !User.IsInRole(CCRoles.RoleNames.EventContentEditor)
                 && !User.IsInRole(CCRoles.RoleNames.EventTrackLead))
            {
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });
            }

            var model = new ScheduleHotelsViewModel();
            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }


    const string BuildingViewRoles = CCRoles.RoleNames.EventContentEditor + ", " + CCRoles.RoleNames.EventTrackLead + ", " + CCRoles.RoleNames.BigCheeze;
    //const string BuildingEditRoles = CCRoles.RoleNames.EventContentEditor + ", " + CCRoles.RoleNames.BigCheeze;

    [CustomAuthorize(Roles = BuildingViewRoles)]
    public ActionResult Buildings(string eventName)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var model = new ScheduleBuildingsViewModel();
            var buildings = repository.GetBuildings(ccEvent.Id);
            foreach (var building in buildings)
            {
                var buildingModel = new ScheduleBuildingEditViewModel.BuildingEditModel
                {
                    Id = building.Id,
                    Name = building.Name
                };
                var rooms = repository.GetRooms(building.Id);
                foreach (var room in rooms)
                {
                    var roomModel = new RoomEditModel
                    {
                        Id = room.Id,
                        Capacity = room.Capacity,
                        Floor = room.Floor,
                        Name = room.Name,
                        ShowToPublic = room.ShowToPublic
                    };
                    buildingModel.Rooms.Add(roomModel);
                }
                model.Buildings.Add(buildingModel);
            }

            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }

    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult AddBuilding(string eventName)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var model = new ScheduleBuildingEditViewModel
            {
                Building = new ScheduleBuildingEditViewModel.BuildingEditModel()
            };
            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult AddBuilding(string eventName, ScheduleBuildingEditViewModel.BuildingEditModel model)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (ModelState.IsValid)
            {
                var buildingId = repository.GetBuildingId(ccEvent.Id, model.Name);
                if (buildingId != 0)
                    return RedirectToAction("Buildings", new { eventName = DefaultEventShortName });

                CCM.Building building = new CCM.Building
                {
                    Name = model.Name,
                    Event = ccEvent
                };
                repository.EFContext.Buildings.Add(building);
                repository.Save();
                return RedirectToAction("Buildings", new { eventName = eventName });
            }
            var viewModel = new ScheduleBuildingEditViewModel
            {
                Building = model
            };
            SetSharedEventProperties(ccEvent, viewModel, repository);

            return View(viewModel);
        }
    }

    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult AddRoom(string eventName, int id)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var building = repository.GetBuildings(ccEvent.Id)
                                .Where(b => b.Id == id)
                                .FirstOrDefault();

            if (building == null)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var model = new ScheduleRoomEditViewModel
            {
                Room = new RoomEditModel
                {
                    ShowToPublic = true
                }
            };
            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult AddRoom(string eventName, int id, RoomEditModel model)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var building = repository.GetBuildings(ccEvent.Id)
                                .Where(b => b.Id == id)
                                .FirstOrDefault();

            if (building == null)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (ModelState.IsValid)
            {
                var roomId = repository.GetRoomId(building.Id, model.Name);
                if (roomId != 0)
                    return RedirectToAction("Buildings", new { eventName = DefaultEventShortName });

                CCM.Room room = new CCM.Room
                {
                    Building = building,
                    Name = model.Name,
                    Capacity = model.Capacity,
                    Floor = model.Floor,
                    ShowToPublic = model.ShowToPublic
                };
                repository.EFContext.Rooms.Add(room);
                repository.Save();
                return RedirectToAction("Buildings", new { eventName = eventName });
            }
            var viewModel = new ScheduleRoomEditViewModel
            {
                Room = model
            };
            SetSharedEventProperties(ccEvent, viewModel, repository);

            return View(viewModel);
        }
    }

    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult EditRoom(string eventName, int id)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var room = repository.GetRoom(id);

            if (room == null)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var model = new ScheduleRoomEditViewModel
            {
                Room = new RoomEditModel
                {
                    Capacity = room.Capacity,
                    Floor = room.Floor,
                    Id = room.Id,
                    Name = room.Name,
                    ShowToPublic = room.ShowToPublic
                }
            };
            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult EditRoom(string eventName, int id, RoomEditModel model)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var room = repository.GetRoomWithBuilding(id);

            if (room == null)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (model.Id != room.Id)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (ModelState.IsValid)
            {
                try
                {
                    room.Capacity = model.Capacity;
                    room.Floor = model.Floor;
                    room.Name = model.Name;
                    room.ShowToPublic = model.ShowToPublic;
                    repository.Save();
                    return RedirectToAction("Buildings", new { eventName = eventName });
                }
                catch (System.Data.Entity.Validation.DbEntityValidationException ex)
                {
                    LogException("Schedule-EditRoom", ex);
                    if (ex.EntityValidationErrors != null)
                    {
                        foreach (System.Data.Entity.Validation.DbEntityValidationResult result in ex.EntityValidationErrors)
                        {
                            foreach (var valErr in result.ValidationErrors)
                            {
                                ModelState.AddModelError("", valErr.ErrorMessage);
                            }
                        }
                    }
                }
            }
            var viewModel = new ScheduleRoomEditViewModel
            {
                Room = model
            };
            SetSharedEventProperties(ccEvent, viewModel, repository);

            return View(viewModel);
        }
    }

    [CustomAuthorize(Roles = BuildingViewRoles)]
    public ActionResult Timeslots(string eventName)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var model = new ScheduleTimeslotsViewModel();
            var timeslots = repository.GetTimeslots(ccEvent.Id);
            foreach (var timeslot in timeslots)
            {
                var timeslotModel = new TimeslotEditModel
                {
                    Id = timeslot.Id,
                    Name = timeslot.Name,
                    StartTime = DateTimeHelper.CombineDateAndTime(timeslot.Date, timeslot.StartTime),
                    EndTime = DateTimeHelper.CombineDateAndTime(timeslot.Date, timeslot.EndTime)
                };
                model.TimeSlots.Add(timeslotModel);
            }

            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }


    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult AddTimeslot(string eventName)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var model = new ScheduleTimeslotEditViewModel()
            {
                Timeslot = new TimeslotEditModel()
                {
                    StartTime = DateTimeHelper.CombineDateAndTime(ccEvent.EventStartDate, new TimeSpan(0)),
                    EndTime = DateTimeHelper.CombineDateAndTime(ccEvent.EventStartDate, new TimeSpan(0))
                }
            };

            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }


    [AcceptVerbs(HttpVerbs.Post)]
    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult AddTimeslot(string eventName, TimeslotEditModel model)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (ModelState.IsValid)
            {
                DateTime slotDate = new DateTime(model.StartTime.Year, model.StartTime.Month, model.StartTime.Day);
                TimeSpan startTime = new TimeSpan(model.StartTime.Hour, model.StartTime.Minute, model.StartTime.Second);
                var timeslot = repository.GetTimeslots(ccEvent.Id)
                                    .Where(t => t.Date == slotDate)
                                    .Where(t => t.StartTime == startTime)
                                    .FirstOrDefault();

                if (timeslot != null)
                {
                    ModelState.AddModelError("", string.Format("Timeslot already exists with date {0} and start time {1}:{2:00}.", 
                        slotDate.ToShortDateString(),
                        startTime.Hours,
                        startTime.Minutes));
                }
                else
                {
                    CCM.Timeslot newTimeslot = new CCM.Timeslot
                    {
                        Date = slotDate,
                        StartTime = startTime,
                        EndTime = new TimeSpan(model.EndTime.Hour, model.EndTime.Minute, model.EndTime.Second),
                        Name = model.Name,
                        Event = ccEvent
                    };
                    repository.EFContext.Timeslots.Add(newTimeslot);
                    repository.Save();
                    return RedirectToAction("Timeslots", new { eventName = DefaultEventShortName });
                }
            }
            var viewModel = new ScheduleTimeslotEditViewModel()
            {
                Timeslot = new TimeslotEditModel()
            };

            SetSharedEventProperties(ccEvent, viewModel, repository);

            return View(viewModel);
        }
    }


    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult EditTimeslot(string eventName, int id)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var timeslot = repository.GetTimeslot(ccEvent.Id, id);
            if (timeslot == null)
                return RedirectToAction("Timeslots", new { eventName = DefaultEventShortName });

            var model = new ScheduleTimeslotEditViewModel()
            {
                Timeslot = new TimeslotEditModel()
                {
                    Id = timeslot.Id,
                    Name = timeslot.Name,
                    StartTime = DateTimeHelper.CombineDateAndTime(timeslot.Date, timeslot.StartTime),
                    EndTime = DateTimeHelper.CombineDateAndTime(timeslot.Date, timeslot.EndTime)
                }
            };

            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }


    [AcceptVerbs(HttpVerbs.Post)]
    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult EditTimeslot(string eventName, int id, TimeslotEditModel model)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (ModelState.IsValid)
            {
                var timeslot = repository.GetTimeslot(ccEvent.Id, id);
                if ((timeslot == null) || (timeslot.Id != model.Id))
                    return RedirectToAction("Timeslots", new { eventName = DefaultEventShortName });

                DateTime slotDate = new DateTime(model.StartTime.Year, model.StartTime.Month, model.StartTime.Day);
                TimeSpan startTime = new TimeSpan(model.StartTime.Hour, model.StartTime.Minute, model.StartTime.Second);
                TimeSpan endTime = new TimeSpan(model.EndTime.Hour, model.EndTime.Minute, model.EndTime.Second);
                if ((timeslot.Date != slotDate) || (timeslot.StartTime != startTime) || (timeslot.EndTime != endTime)
                    || (timeslot.Name != model.Name))
                {
                    timeslot.Date = slotDate;
                    timeslot.StartTime = startTime;
                    timeslot.EndTime = endTime;
                    timeslot.Name = model.Name;
                    repository.Save();
                }
                return RedirectToAction("Timeslots", new { eventName = DefaultEventShortName });
            }
            var viewModel = new ScheduleTimeslotEditViewModel()
            {
                Timeslot = model
            };

            SetSharedEventProperties(ccEvent, viewModel, repository);

            return View(viewModel);
        }
    }

    private void FillScheduleGridViewModel(CCM.Event ccEvent, CodeCampDataRepository ccdr, ScheduleGridModel model)
    {
        var buildings = ccdr.GetBuildings(ccEvent.Id);
        model.BuildingCount = 0;
        model.CapacityCount = 0;
        List<int> floors = new List<int>();
        model.Rooms.Clear();
        model.Timeslots.Clear();
        model.EventShortName = ccEvent.ShortName;
        foreach (var building in buildings.OrderBy(b => b.Name))
        {
            model.BuildingCount++;
            foreach (var room in building.Rooms.OrderBy(r => r.Floor))
            {
                if (room.ShowToPublic || User.IsInRole(CCRoles.RoleNames.BigCheeze))
                {
                    if ((room.Floor.HasValue) && !floors.Contains(room.Floor.Value))
                    {
                        floors.Add(room.Floor.Value);
                    }
                    if (room.Capacity > 0)
                        model.CapacityCount++;

                    model.Rooms.Add(room.Id,
                        new ScheduleGridModel.Room
                        {
                            Building = building.Name,
                            Capacity = room.Capacity,
                            Floor = room.Floor,
                            RoomName = room.Name,
                            RoomId = room.Id,
                            ShowToPublic = room.ShowToPublic
                        }
                        );
                }
            }
            model.FloorCount = floors.Count;
        }
        var timeslots = ccdr.GetTimeslots(ccEvent.Id)
            .OrderBy(t => t.StartTime);
        foreach (var timeslot in timeslots)
        {
            var timeslotView = new ScheduleGridModel.Timeslot
            {
                TimeslotId = timeslot.Id,
                StartTime = DateTimeHelper.CombineDateAndTime(timeslot.Date, timeslot.StartTime),
                EndTime = DateTimeHelper.CombineDateAndTime(timeslot.Date, timeslot.EndTime),
                Name = timeslot.Name,
                SessionCount = 0
            };
            foreach (var room in model.Rooms
                .OrderBy(r => r.Value.Building)
                .ThenBy(r => r.Value.Floor)
                .ThenBy(r => r.Value.RoomName))
            {
                if (room.Value.ShowToPublic || User.IsInRole(CCRoles.RoleNames.BigCheeze))
                {
                    timeslotView.GridCells.Add(room.Value.RoomId, new ScheduleGridModel.Timeslot.GridCell
                    {
                        CellRoom = room.Value,
                        RoomId = room.Value.RoomId
                    });
                }
            }
            model.Timeslots.Add(timeslotView.TimeslotId, timeslotView);

            var scheduledSessions = timeslot.ScheduledSessions.OrderBy(ss => ss.Session.Title);
            foreach (var ss in scheduledSessions)
            {
                if (!timeslotView.GridCells.ContainsKey(ss.RoomId))
                {
                    model.ErrorMsgs.AppendFormat("Room({1}) \"{2}\" not found for timeslot({3}) {4}:{5:00} {0}",
                        Environment.NewLine,
                        ss.RoomId,
                        ss.Room.Name,
                        timeslot.Id,
                        timeslot.StartTime.Hours,
                        timeslot.StartTime.Minutes);
                }
                else
                {
                    var gridCell = timeslotView.GridCells[ss.RoomId];
                    var session = new ScheduleGridModel.Timeslot.Session
                    {
                        RoomId = ss.RoomId,
                        SessionId = ss.SessionId,
                        TimeslotId = timeslot.Id,
                        Title = SessionTitle(ss.Session)
                    };
                    gridCell.Sessions.Add(session);
                    //model.Sessions.Add(session.SessionId, session);
                    timeslotView.SessionCount++;
                }
            }
        }
    }

    private void FillUnscheduledSessionList(CCM.Event ccEvent, CodeCampDataRepository ccdr, ScheduleAddSessionModel model)
    {
        model.UnscheduledSessions.Clear();

        var unscheduledSessions = ccdr.GetUnscheduledSessions(ccEvent.Id);

        foreach (var unschedSession in unscheduledSessions.OrderBy(s => s.Title))
        {
            model.UnscheduledSessions.Add(new ScheduleAddSessionModel.Session
            {
                SessionId = unschedSession.Id,
                DesiredRoomSize = unschedSession.DesiredRoomSize,
                Status = unschedSession.Status,
                Title = unschedSession.Title
            });
        }
    }

    private void FillRoomsList(ScheduleGridModel gridModel, ScheduleAddSessionModel addModel)
    {
        foreach (var room in gridModel.Rooms)
        {
            addModel.Rooms.Add(new ScheduleAddSessionModel.Room
            {
                RoomId = room.Value.RoomId,
                Name = room.Value.RoomName
            });
        }
    }

    private void FillTimeSlotList(ScheduleGridModel gridModel, ScheduleAddSessionModel addModel)
    {
        foreach (var timeslot in gridModel.Timeslots)
        {
            addModel.Timeslots.Add(new ScheduleAddSessionModel.Timeslot
            {
                EndTime = timeslot.Value.EndTime,
                Name = timeslot.Value.Name,
                SessionCount = timeslot.Value.SessionCount,
                StartTime = timeslot.Value.StartTime,
                TimeslotId = timeslot.Value.TimeslotId.ToString()
            });
        }
    }

    public ActionResult SessionGrid(string eventName)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (!CanShowSchedule(ccEvent))
            {
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });
            }

            var model = new ScheduleGridViewModel
            {
                ScheduleGrid = new ScheduleGridModel()
            };

            FillScheduleGridViewModel(ccEvent, repository, model.ScheduleGrid);

            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }

    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult EditSchedule(string eventName)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            var model = new ScheduleEditViewModel
            {
                AddSessionModel = new ScheduleAddSessionModel
                {
                    EventShortName = ccEvent.ShortName,
                    SessionAddAction = true
                },
                ScheduleGrid = new ScheduleGridEditModel
                {
                    GridEditAction = true
                }
            };

            FillUnscheduledSessionList(ccEvent, repository, model.AddSessionModel);
            FillScheduleGridViewModel(ccEvent, repository, model.ScheduleGrid);
            FillRoomsList(model.ScheduleGrid, model.AddSessionModel);
            FillTimeSlotList(model.ScheduleGrid, model.AddSessionModel);

            SetSharedEventProperties(ccEvent, model, repository);

            return View(model);
        }
    }

    [AcceptVerbs(HttpVerbs.Post)]
    [CustomAuthorize(Roles = CCRoles.RoleNames.BigCheeze)]
    public ActionResult EditSchedule(string eventName, ScheduleAddSessionModel model, ScheduleGridEditModel model2, int[] sessionsToRemove)
    {
        using (var repository = new CodeCampDataRepository())
        {
            var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            if (ccEvent.ShortName != eventName)
                return RedirectToAction("Index", "Home", new { eventName = DefaultEventShortName });

            if (ModelState.IsValid)
            {
                if (model.SessionAddAction)
                {
                    int roomId = 0;
                    int timeslotId = 0;

                    if (string.IsNullOrEmpty(model.RoomId) || !Int32.TryParse(model.RoomId, out roomId))
                    {
                        ModelState.AddModelError("", "You must select a room.");
                    }
                    if (string.IsNullOrEmpty(model.TimeslotId) || !Int32.TryParse(model.TimeslotId, out timeslotId))
                    {
                        ModelState.AddModelError("", "You must select a timeslot.");
                    }
                    if (model.SessionId == 0)
                    {
                        ModelState.AddModelError("", "You must select a session.");
                    }

                    if (ModelState.IsValid)
                    {
                        var room = repository.GetRoom(roomId);
                        if ((room == null) || (room.Building.EventId != ccEvent.Id))
                        {
                            ModelState.AddModelError("", string.Format("Internal error - invalid roomId ({0}).", roomId));
                        }
                        var session = repository.GetSession(ccEvent.Id, model.SessionId);
                        if (session == null)
                        {
                            ModelState.AddModelError("", string.Format("Internal error - invalid SessionId ({0}).", model.SessionId));
                        }
                        var timeslot = repository.GetTimeslot(ccEvent.Id, timeslotId);
                        if (timeslot == null)
                        {
                            ModelState.AddModelError("", string.Format("Internal error - invalid timeslotId ({0}).", timeslotId));
                        }
                        if (ModelState.IsValid)
                        {
                            var scheduledSession = new CCM.ScheduledSession
                            {
                                Room = room,
                                Session = session,
                                Timeslot = timeslot
                            };
                            if (session.SessionStatusId != (int)CCM.Session.SessionStatus.Selected)
                                session.SessionStatusId = (int)CCM.Session.SessionStatus.Selected;
                            repository.EFContext.ScheduledSessions.Add(scheduledSession);
                            repository.Save();
                            return RedirectToAction("EditSchedule", new { eventName = eventName });
                        }
                    }
                }
                else if (model2.GridEditAction)
                {
                    if (sessionsToRemove != null)
                    {
                        foreach (int sessionId in sessionsToRemove)
                        {
                            var scheduleSession = repository.GetScheduledSession(sessionId);
                            if (scheduleSession == null)
                            {
                                ModelState.AddModelError("", string.Format("Internal error - invalid SessionId ({0}).", sessionId));
                            }
                            else if (scheduleSession.Timeslot.EventId != ccEvent.Id)
                            {
                                ModelState.AddModelError("", string.Format("Internal error - invalid SessionId ({0}) not part of event.", sessionId));
                            }
                            else
                            {
                                repository.EFContext.ScheduledSessions.Remove(scheduleSession);
                                repository.Save();
                                return RedirectToAction("EditSchedule", new { eventName = eventName });
                            }
                        }
                    }
                }
            }
            var viewModel = new ScheduleEditViewModel
            {
                AddSessionModel = model,
                ScheduleGrid = model2
            };
            viewModel.AddSessionModel.SessionAddAction = true;
            viewModel.ScheduleGrid.GridEditAction = true;

            FillUnscheduledSessionList(ccEvent, repository, viewModel.AddSessionModel);
            FillScheduleGridViewModel(ccEvent, repository, viewModel.ScheduleGrid);
            FillRoomsList(viewModel.ScheduleGrid, viewModel.AddSessionModel);
            FillTimeSlotList(viewModel.ScheduleGrid, viewModel.AddSessionModel);

            SetSharedEventProperties(ccEvent, viewModel, repository);

            return View(viewModel);
        }
    }


  }
}
